#pragma once
#pragma warning (disable: 4996)

#include "ImageLab.h"
#include <vector>
#include "BasicFunction.h"
using namespace std;

struct somnode
{
	_3dpoint position;
	vector<double> weight;
};

class MultiscaleNet
{
public:
	//Constructor and deconstructor
	MultiscaleNet(unsigned int sizex, unsigned int sizey, unsigned int sizez, unsigned int numberofdata, unsigned int maxcycle, vector<double> maxvalue,
		vector<double> minvalue);
	MultiscaleNet(unsigned int sizex, unsigned int sizey, unsigned int sizez, unsigned int numberofdata, unsigned int maxcycle);
	MultiscaleNet(string filepath);
	~MultiscaleNet(void);
//Members:
	//Attributes of the SOM
	vector<vector<vector<somnode>>>		somoutputlayer;				//lattice of the SOM
	_3dpoint			sizeofsom;							//size of the SOM
	double				neighborhoodsize;				//neighborhoodsize
	double				neighborhoodscale;			//change scale of the neighborhood size
	double				learningrate;						//learning rate
	double				learningratescale;				//change scale of the learning rate
	double				initialrate;							//initial learning rate;
	double				finalrate;							//final learning rate;
	double				initialsize;							//initial neighborhood size;
	double				finalsize;							//final neighborhood size;
	unsigned int		datadimension;					//data dimension of the SOM
	unsigned int		trainingcycle;						//training cycle of the SOM
	unsigned int		mapradius;						//radius of the map
	CBasicFunction	bf;								//Basic functions
	//Temporal output of the SOM
	unsigned int				currentiteration;					//current iteration
	unsigned int				currentcycle;						//current cycle
	vector<double>		trainingdistance;				//distance between the input and the node during training
	vector<vector<unsigned int> >				outputpattern;					//patterns on the output layer
	vector<vector<vector<int> > >	outputpatterncount;		//count the patterns occurrences on the output layer

//Function:
	//Position between two vectors
	double			Distance(vector<double> vector1, vector<double> vector2);
	//Find the winner for an input
	_3dpoint		FindWinner(vector<vector<double>> input);
	_3dpoint		FindWinner(vector<vector<double>> input, double& distance);
	//Update the weights around the winner
	void				UpdateWeights(_3dpoint winner, vector<vector<double>> input);
	void				UpdateWeights(_3dpoint winner, vector<vector<double> > input, unsigned int inputpattern);
	//Get a testing result
	void				GetTestWinnerWeight(vector<vector<double>> testinput, _3dpoint& position, vector<vector<double>>& weight);
	void				GetTestWinnerWeight(vector<vector<double> > testinput, _3dpoint& position, vector<vector<double> >& weight, unsigned int& pattern);
	//Get weights of training winners
	void				Training(vector<vector<vector<double>>> trainingdata, vector<_3dpoint>& trainingwinners,
						vector<vector<vector<double>>>& trainingweights);
	void				Training(vector<vector<vector<double> > > trainingdata, vector<unsigned int> inputpattern,
							vector<_3dpoint>& trainingwinners,	vector<vector<vector<double> > >& trainingweights);
	//Genrate a double vector
	vector<double> GenerateDoubleVector(vector<double> maxvalue, vector<double> minvalue);
	vector<double> GenerateDoubleVector(unsigned int numberofdata);
	//Save the weights to file
	void				SaveWeightsToFile(string filename);
	//Get the size of the SOM
	_3dpoint		GetNetSize();
	//Get the distances between the input and the output nodes at each iteration during training
	vector<double>	GetDistances(void);
	//Save the net into a file
	void				SaveNetIntoFile(string filename);
	//Load the net from a file
	void				LoadNetFromFile(string filename);
	//Get lattice pattern
	vector<vector<unsigned int> > GetOutputPattern(void);
};
